// Copyright (c) 2008 Matthew Johnson
// Licensed under the MIT License (see license.txt)
package actionml.core {
	import actionml.Global;
	
	import flash.utils.describeType;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	import flash.utils.getQualifiedSuperclassName;
	
	public class ClassMethods {
		public static function initialize() {
			Global.initializeExtension(ClassMethods, Class);
		}
		public static var staticMethods:Object = {
			forName: function(name:String) {
				var defaultPackages:Array = ["flash.display", "flash.filters", "flash.geom", "flash.text", "fl.controls", "fl.containers", "fl.motion", "fl.motion.easing", "fl.transitions", "fl.transitions.easing"];
				var c:Class;
				try {
					return Class(getDefinitionByName(name));
				} catch (e:Error) { }
				for each (var packageName:String in defaultPackages) {
					try {
						return Class(getDefinitionByName(packageName + "." + name));
					} catch (e2:Error) { }
				}
				return null;
			}
		};
		public static var instanceMethods:Object = {
			toString: function() {
				return getQualifiedClassName(this);
			},
			
			getSuperclassName: function() {
				return getQualifiedSuperclassName(this);
			},
			getSuperclass: function() {
				if (this == Object) { return null; }
				return getDefinitionByName(getQualifiedSuperclassName(this));
			},
			getClassHierarchy: function() {
				var r:Array = [];
				var c:Class = this;
				while (c != null) {
					r.push(c);
					c = Object(c).getSuperclass();
				} 
				return r;
			},
			
			getConstants: function() {
				var r:Object = {};
				for each (var node:XML in describeType(this).constant) {
					r[node.@name] = this[node.@name];
				}
				return r;
			},			
			getConstantNames: function() {
				var r:Array = [];
				for each (var node:XML in describeType(this).constant) {
					r.unshift(node.@name);
				}
				return r;
			},
			getConstantValues: function() {
				var r:Array = [];
				for each (var node:XML in describeType(this).constant) {
					r.unshift(this[node.@name]);
				}
				return r;
			},
			
			getMethods: function() {
				var r:Object = {};
				for each (var node:XML in describeType(this)..method) {
					r[node.@name] = this[node.@name];
				}
				return r;
			},
			getMethodNames: function() {
				var r:Array = [];
				for each (var node:XML in describeType(this)..method) {
					r.unshift(node.@name);
				}
				return r;
			},
			
			getProperties: function() {
				var r:Object = {};
				for each (var node:XML in describeType(this)..variable) {
					r[node.@name] = this[node.@name];
				}
				for each (node in describeType(this)..accessor) {
					if (node.@acceess == "readwrite" || node.@acceess == "readonly") {
						r[node.@name] = this[node.@name];
					}
				}
				return r;
			},
			getPropertyNames: function(includeReadOnly:Boolean=true) {
				var r:Array = [];
				for each (var node:XML in describeType(this)..variable) {
					r.unshift(node.@name);
				}
				for each (node in describeType(this)..accessor) {
					if (node.@acceess == "readwrite") {
						r.unshift(node.@name);
					}
					if (includeReadOnly && node.@acceess == "readonly") {
						r.unshift(node.@name);
					}
				}
				if (includeReadOnly) {
					for each (var c:Class in this.getClassHierarchy()) {
						for (var s:String in c.prototype) {
							trace(s)
							r.unshift(s);
						}
					}
				}
				return r;
			},
			
			getTracer: function(o:Object) {
				var c:Class = Class["forName"]("actionml.tracing.Tracer");
				if (c) {
					o ||= {};
					o.className = this.toString();
					return new c(o);
				} else {
					o = {};
					for each (var s:String in ["test", "assert", "trace", "info", "warn", "error", "critical"]) { 
						o[s] = function() {};
					}
					return o;
				}
			}
		};
	}
}